package varredor;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.util.List;
import javax.swing.UIManager;
import varredor.concorrencia.Semaforo;
import varredor.model.Cenario;
import varredor.model.ComputadorNo;
import varredor.model.Varredor;
import varredor.rmi.ArquivoCompartilhado;
import varredor.rmi.ArquivoCompartilhadoImpl;
import varredor.view.PrincipalFrame;
import varredor.view.VisualizarVarredoresFrame;
import varredor.web.ConexaoBroadcast;
import varredor.web.RecebeuMensagemListener;

public class StartPoint implements RecebeuMensagemListener {

	private ConexaoBroadcast conexaoBroad;
	private PrincipalFrame principal;

	private static StartPoint INSTANCE;

	private Semaforo semCenario = new Semaforo();

	private Cenario cenario;

	private String IP = "";
	private String MAC = "";
	private String BROADCAST = "";

	private VisualizarVarredoresFrame varredoresFrame;

	private boolean montandoLista = false;

	private ServerSocket serverSocket;

	public static void main(String[] args) throws Exception {

		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}

		INSTANCE = new StartPoint();
		INSTANCE.start();
	}

	private void start() throws Exception {

		semCenario.setNome("SEMAFORO CENARIO");
		semCenario.setDebug(true);
		iniciarVariaveisRede("net5");

		conexaoBroad = new ConexaoBroadcast(InetAddress.getByName(BROADCAST), this);

		iniciarObjetoRMI();

		//TESTE
		//conexaoBroad.envia(RecebeuMensagemListener.MSG_ESTA_ONLINE);

		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					serverSocket = new ServerSocket(7000);

					while (true) {
						serverSocket.accept();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();

		principal = new PrincipalFrame();
		principal.setLocationRelativeTo(null);

		varredoresFrame = new VisualizarVarredoresFrame();

		principal.setVisible(true);
	}

	private void iniciarVariaveisRede(String rede) throws Exception {
		NetworkInterface networkInterface = NetworkInterface.getByName(rede);

		System.out.println(networkInterface.getName() + "  -  " + networkInterface.getDisplayName());

		List<InterfaceAddress> enumInterface = networkInterface.getInterfaceAddresses();
		for (InterfaceAddress interfaceAddress : enumInterface) {
			int prefix = interfaceAddress.getNetworkPrefixLength();
			System.out.println(prefix);

			System.out.println("IP: " + interfaceAddress.getAddress());

			IP = interfaceAddress.getAddress().getHostAddress();

			if (interfaceAddress.getBroadcast() == null)
				continue;

			System.out.println("Broad: " + interfaceAddress.getBroadcast());

			BROADCAST = interfaceAddress.getBroadcast().getHostAddress();
			BROADCAST = "255.255.255.255";
			break;
		}
		if (networkInterface.getHardwareAddress() != null) {
			StringBuilder macBuilder = new StringBuilder();
			for (byte b : networkInterface.getHardwareAddress()) {
				macBuilder.append(Integer.toHexString(b).replaceAll("ffffff", "").toUpperCase());
			}

			macBuilder.insert(2, '-');
			macBuilder.insert(5, '-');
			macBuilder.insert(8, '-');
			macBuilder.insert(11, '-');
			macBuilder.insert(14, '-');

			System.out.println("MAC: " + macBuilder.toString());
			MAC = macBuilder.toString();
		}

	}

	private static void iniciarObjetoRMI() {

		try {
			LocateRegistry.createRegistry(1099);
			ArquivoCompartilhadoImpl obj = new ArquivoCompartilhadoImpl();
			Naming.rebind("ArquivoCompartilhado", obj);

			System.out.println("ArquivoCompartilhado foi criado e registrado");
		} catch (Exception e) {
			System.out.println("Ocorreu uma exceção no servidor");
			e.printStackTrace();
		}
	}

	public String getMAC() {
		return MAC;
	}

	public String getIP() {
		return IP;
	}

	public String getBROADCAST() {
		return BROADCAST;
	}

	@Override
	public void recebeu(InetAddress address, String mensagem) {

		//Desconsidera caso a mensagem tenha vindo da propria maquina.
		if (address.getHostAddress().equals(getIP())) {
			System.out.println("ME TIREI DA RESPOSTA DE BROAD CAST.....");
			return;
		}

		//		if (mensagem.startsWith(RecebeuMensagemListener.MSG_ESTA_ONLINE)) {
		//			//Responder apenas para quem enviou a menagem.
		//			try {
		//				responderParaComputador(address);
		//			} catch (Exception e) {
		//				e.printStackTrace();
		//			}
		//		}

		if (mensagem.startsWith(RecebeuMensagemListener.MSG_ATUALIZA)) {

			new Thread(new Runnable() {
				@Override
				public void run() {
					montarListaComputadores();

					new Thread(new Varredor()).start();
				}
			}).start();
		}
	}

	protected void montarListaComputadores() {

		if (cenario != null || montandoLista)
			return;

		int ultimoIndice = getIP().lastIndexOf('.');
		String ipMutavel = getIP().substring(0, ultimoIndice);

		System.out.println(ipMutavel);

		montandoLista = true;

		for (int i = 1; i < 254; i++) {
			String ipTest = ipMutavel + "." + i;
			if (ipTest.equals(getIP()))
				continue;

			int time = 150;
			try {

				Socket socket = new Socket();
				socket.setSoTimeout(time);
				socket.setSoLinger(false, 0);
				socket.connect(new InetSocketAddress(ipTest, 7000), time);

				socket.close();

				ArquivoCompartilhado stub = (ArquivoCompartilhado) Naming.lookup("rmi://" + ipTest + "/ArquivoCompartilhado");

				adicionarComputador(ipTest, stub.getMac());
			} catch (Exception e) {
				System.err.println("Não está online " + ipTest);
				//e.printStackTrace();
			}
		}
		montandoLista = false;
	}

	public void adicionarComputador(String hostAddress, String mac) {

		semCenario.DOWN();

		System.out.println("ESSE COMPUTADOR ESTÁ ONLINE : " + hostAddress);

		if (cenario == null)
			cenario = new Cenario();

		ComputadorNo no = new ComputadorNo();
		no.setIp(hostAddress);
		no.setMac(mac);
		no.setOnline(true);

		cenario.addNo(no);

		if (varredoresFrame != null && !varredoresFrame.isVisible()) {
			varredoresFrame.setVisible(true);
			varredoresFrame.iniciarVarreduraCenario();
		}
		semCenario.UP();
	}

	public void termineiVarredura() {
		semCenario.DOWN();

		if (cenario.podeEncerrar())
			cenario = null;

		semCenario.UP();
	}

	public ConexaoBroadcast getConexaoBroad() {
		return conexaoBroad;
	}

	public PrincipalFrame getPrincipal() {
		return principal;
	}

	public static StartPoint getINSTANCE() {
		return INSTANCE;
	}

	public Cenario getCenario() {
		return cenario;
	}

	public void adicionarNovoVarredor() throws Exception {
		if (cenario == null || montandoLista)
			throw new Exception("Não foram identicados todos os computadores da rede");

		new Thread(new Varredor()).start();
	}

	public void visualizarVarredores() {
		if (!varredoresFrame.isVisible())
			varredoresFrame.setVisible(true);
	}
}
